package cn.lingyangwl.agile.system.service.impl;

import cn.lingyangwl.agile.auth.AuthApi;
import cn.lingyangwl.agile.common.security.constants.DataRuleEnum;
import cn.lingyangwl.agile.model.enums.BoolEnum;
import cn.lingyangwl.agile.system.assembly.SysMenuAssembly;
import cn.lingyangwl.agile.system.manager.SysUserManager;
import cn.lingyangwl.agile.system.mapper.SysMenuDataRuleMapper;
import cn.lingyangwl.agile.system.mapper.SysRoleMenuRelMapper;
import cn.lingyangwl.agile.system.model.entity.SysMenuRule;
import cn.lingyangwl.agile.system.model.entity.SysRoleMenu;
import cn.lingyangwl.agile.system.model.rqrs.menu.MenuDataRuleListReq;
import cn.lingyangwl.agile.system.model.rqrs.menu.MenuDataRuleSaveReq;
import cn.lingyangwl.agile.system.service.SysMenuDataRuleService;
import cn.lingyangwl.framework.tool.core.CollectionUtils;
import cn.lingyangwl.framework.tool.core.SqlUtils;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.Assert;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Service
public class SysMenuDataRuleServiceImpl implements SysMenuDataRuleService {
    @Resource
    private SysMenuDataRuleMapper sysMenuDataRuleMapper;

    @Resource
    private SysRoleMenuRelMapper sysRoleMenuRelMapper;
    @Resource
    private SysMenuAssembly sysMenuAssembly;
    @Resource
    private AuthApi authApi;
    @Resource
    private SysUserManager sysUserManager;

    @Override
    public List<SysMenuRule> listPermissionRule(String permissionId) {
        LambdaQueryWrapper<SysMenuRule> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysMenuRule::getMenuId, permissionId);
        lqw.eq(SysMenuRule::getStatus, BoolEnum.TRUE.getCode());
        return sysMenuDataRuleMapper.selectList(lqw);
    }

    @Override
    public List<SysMenuRule> listPermissionRule(MenuDataRuleListReq req) {
        SysMenuRule sysMenuRule = sysMenuAssembly.toMenuRule(req);

        LambdaQueryWrapper<SysMenuRule> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysMenuRule::getMenuId, sysMenuRule.getMenuId());
        return sysMenuDataRuleMapper.selectList(lqw);
    }

    @Override
    public List<SysMenuRule> listPermissionRule(List<Long> roleIds, List<Long> permissionIds) {
        if (CollectionUtils.isEmpty(roleIds) || CollectionUtils.isEmpty(permissionIds)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<SysRoleMenu> sysRoleMenuRelLqw = new LambdaQueryWrapper<>();
        sysRoleMenuRelLqw.in(SysRoleMenu::getRoleId, roleIds)
                .and((qw) -> qw.in(SysRoleMenu::getMenuId, permissionIds));
        List<SysRoleMenu> menuRelPOList = sysRoleMenuRelMapper.selectList(sysRoleMenuRelLqw);

        Set<String> dataRuleIds = new HashSet<>();
        for (SysRoleMenu item : menuRelPOList) {
            if (StringUtils.isNotEmpty(item.getDataRuleIds())) {
                dataRuleIds.addAll(StringUtils.toList(item.getDataRuleIds(), ",", String.class));
            }
        }
        if (dataRuleIds.isEmpty()) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<SysMenuRule> lqw = new LambdaQueryWrapper<>();
        lqw.in(SysMenuRule::getId, dataRuleIds);
        return sysMenuDataRuleMapper.selectList(lqw);
    }

    @Override
    public void savePermissionRule(MenuDataRuleSaveReq req) {
        SysMenuRule menuRule = sysMenuAssembly.toMenuRule(req);
        checkRule(menuRule);
        if (sysMenuDataRuleMapper.insert(menuRule) <= 0) {
            throw new BizException("保存失败, 请联系管理员!!!");
        }
    }

    @Override
    public void updatePermissionRule(SysMenuRule req) {
        checkRule(req);
        Assert.notNull(req.getId(), "请选择数据规则");
        sysMenuDataRuleMapper.updateById(req);

        // 获取引用该规则的用户
        List<Long> roleIds = sysRoleMenuRelMapper.selectList(SysRoleMenu.lqw().eq(SysRoleMenu::getMenuId, req.getMenuId()))
                .stream().map(SysRoleMenu::getRoleId).distinct().collect(Collectors.toList());
        List<Long> userIds = sysUserManager.listUserIdsByRoleIds(roleIds);
        // 由于数据规则已经被更改, 使所有用户重新登录
        authApi.removeAccessTokenByUserIds(userIds);
    }

    private void checkRule(SysMenuRule in) {
        if (DataRuleEnum.DATA_MY.getCondition().equals(in.getRuleConditions()) ||
                DataRuleEnum.DATA_MY_CURRENT_DEPT.getCondition().equals(in.getRuleConditions()) ||
                DataRuleEnum.DATA_MY_ALL_DEPT.getCondition().equals(in.getRuleConditions())) {
            in.setRuleValue("");
        } else {
            if (SqlUtils.containsSqlInjection(in.getRuleValue())) {
                throw new BizException("非法规则值, 不能包含 [ \" | % | + | ; ] 等字符");
            }
        }
    }

    @Override
    public void deletePermissionRule(String dataRoleId) {
        sysMenuDataRuleMapper.deleteById(dataRoleId);
    }
}
